package org.dxy.trigger.http.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dxy.api.dto.*;
import org.dxy.api.response.R;
import org.dxy.domain.port.CommandHandler;
import org.dxy.domain.command.process.*;
import org.dxy.infrastructure.persistent.db.mybatispuls.po.query.ProcessExecutionViewPo;
import org.dxy.infrastructure.persistent.db.mybatispuls.po.query.ProcessViewPo;
import org.dxy.infrastructure.persistent.db.mybatispuls.service.ProcessExecutionViewService;
import org.dxy.infrastructure.persistent.db.mybatispuls.service.ProcessViewService;
import org.dxy.trigger.http.service.ProcessApplicationService;
import org.dxy.types.common.CommandResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 工序应用服务实现类
 * @author dxy
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ProcessApplicationServiceImpl implements ProcessApplicationService {
    
    private final CommandHandler<CreateProcessCommand, Long> createCommandHandler;
    private final CommandHandler<StartProcessCommand, Void> startCommandHandler;
    private final CommandHandler<PauseProcessCommand, Void> pauseCommandHandler;
    private final CommandHandler<ResumeProcessCommand, Void> resumeCommandHandler;
    private final CommandHandler<CompleteProcessCommand, Void> completeCommandHandler;
    private final CommandHandler<ChangeProcessStepCommand, Void> changeStepCommandHandler;
    private final CommandHandler<CheckProcessQualityCommand, Void> checkQualityCommandHandler;
    private final CommandHandler<HoldProcessCommand, Void> holdCommandHandler;
    private final CommandHandler<ReleaseProcessCommand, Void> releaseCommandHandler;
    private final CommandHandler<ReworkProcessCommand, Void> reworkCommandHandler;
    private final CommandHandler<RecordProcessMeasurementCommand, Void> recordMeasurementCommandHandler;
    private final CommandHandler<AssignProcessCommand, Void> assignCommandHandler;
    
    private final ProcessExecutionViewService processExecutionViewService;
    private final ProcessViewService processViewService;

    @Transactional
    @Override
    public R<Long> create(CreateProcessRequestDto dto) {
        try {
            log.info("开始创建工序，请求参数：{}", dto);
            
            // 将DTO转换为命令对象（只包含必要的业务参数）
            CreateProcessCommand command = new CreateProcessCommand(
                    dto.getProcessCode(),
                    dto.getParameters()
            );
            
            // 执行命令端处理(C端)
            CommandResult<Long> result = createCommandHandler.handle(command);
            
            if (!result.success()) {
                log.warn("工序创建失败，原因：{}", result.msg());
                return R.fail(result.msg());
            }
            
            Long processId = result.data();
            ProcessViewPo processViewPo = ProcessViewPo.builder()
                    .id(processId)
                    .processCode(dto.getProcessCode())
                    .processName(dto.getProcessName())
                    .build();
            processViewService.save(processViewPo);
            log.info("工序创建成功，processId={}", processId);
            
            return R.ok(processId, "工序创建成功");
        } catch (Exception e) {
            log.error("工序创建失败", e);
            return R.fail("工序创建失败: " + e.getMessage());
        }
    }
    
    @Override
    public R<Void> start(StartProcessRequestDto dto) {
        try {
            log.info("开始执行工序，请求参数：{}", dto);
            
            // 将DTO转换为命令对象（只包含必要的业务参数）
            StartProcessCommand command = new StartProcessCommand(
                    dto.getProcessId(),
                    dto.getWorkOrderId(),
                    dto.getEquipmentId()
            );
            
            // 1. 执行命令端处理(C端)
            CommandResult<Void> result = startCommandHandler.handle(command);
            
            if (!result.success()) {
                log.warn("工序开始执行失败，原因：{}", result.msg());
                return R.fail(result.msg());
            }
            
            Long processId = dto.getProcessId();
            log.info("工序开始执行成功，processId={}", processId);
            
            // 构造读模型（Q端，包含更多展示信息）
            ProcessExecutionViewPo processExecutionView = ProcessExecutionViewPo.builder()
                    .processId(processId)
                    .workOrderId(dto.getWorkOrderId())
                    .equipmentId(dto.getEquipmentId())
                    .plannedStartTime(dto.getPlannedStartTime())
                    .actualStartTime(LocalDateTime.now())
                    .status("RUNNING")
                    .remarks(dto.getRemarks())
                    .build();
            
            // 保存读模型
            processExecutionViewService.save(processExecutionView);
            log.info("工序执行读模型保存成功，processId={}", processId);
            
            return R.ok("工序开始执行成功");
        } catch (Exception e) {
            log.error("工序开始执行失败", e);
            return R.fail("工序开始执行失败: " + e.getMessage());
        }
    }
    
    @Override
    public R<Void> pause(PauseProcessRequestDto dto) {
        try {
            log.info("开始暂停工序，请求参数：{}", dto);
            
            PauseProcessCommand command = new PauseProcessCommand(
                    dto.getProcessId()
            );
            
            CommandResult<Void> result = pauseCommandHandler.handle(command);
            
            if (!result.success()) {
                log.warn("工序暂停失败，原因：{}", result.msg());
                return R.fail(result.msg());
            }
            
            // 更新读模型（Q端）
            ProcessExecutionViewPo processExecutionView = processExecutionViewService.getById(dto.getProcessId());
            if (processExecutionView != null) {
                processExecutionView.setStatus("PAUSED");
                processExecutionView.setPauseTime(LocalDateTime.now());
                processExecutionView.setPauseReason(dto.getReason());
                processExecutionView.setLastOperator(dto.getOperatorId());
                processExecutionViewService.updateById(processExecutionView);
                log.info("工序执行读模型更新成功，processId={}", dto.getProcessId());
            }
            
            return R.ok("工序暂停成功");
        } catch (Exception e) {
            log.error("工序暂停失败", e);
            return R.fail("工序暂停失败: " + e.getMessage());
        }
    }
    
    @Override
    public R<Void> resume(ResumeProcessRequestDto dto) {
        try {
            log.info("开始恢复工序，请求参数：{}", dto);
            
            ResumeProcessCommand command = new ResumeProcessCommand(
                    dto.getProcessId()
            );
            
            CommandResult<Void> result = resumeCommandHandler.handle(command);
            
            if (!result.success()) {
                log.warn("工序恢复失败，原因：{}", result.msg());
                return R.fail(result.msg());
            }
            
            // 更新读模型（Q端）
            ProcessExecutionViewPo processExecutionView = processExecutionViewService.getById(dto.getProcessId());
            if (processExecutionView != null) {
                processExecutionView.setStatus("RUNNING");
                processExecutionView.setResumeTime(LocalDateTime.now());
                processExecutionView.setLastOperator(dto.getOperatorId());
                processExecutionViewService.updateById(processExecutionView);
                log.info("工序执行读模型更新成功，processId={}", dto.getProcessId());
            }
            
            return R.ok("工序恢复成功");
        } catch (Exception e) {
            log.error("工序恢复失败", e);
            return R.fail("工序恢复失败: " + e.getMessage());
        }
    }
    
    @Override
    public R<Void> complete(CompleteProcessRequestDto dto) {
        try {
            log.info("开始完成工序，请求参数：{}", dto);
            
            CompleteProcessCommand command = new CompleteProcessCommand(
                    dto.getProcessId()
            );
            
            CommandResult<Void> result = completeCommandHandler.handle(command);
            
            if (!result.success()) {
                log.warn("工序完成失败，原因：{}", result.msg());
                return R.fail(result.msg());
            }
            
            // 更新读模型（Q端）
            ProcessExecutionViewPo processExecutionView = processExecutionViewService.getById(dto.getProcessId());
            if (processExecutionView != null) {
                processExecutionView.setStatus("COMPLETED");
                processExecutionView.setCompletedTime(LocalDateTime.now());
                processExecutionView.setLastOperator(dto.getOperatorId());
                processExecutionViewService.updateById(processExecutionView);
                log.info("工序执行读模型更新成功，processId={}", dto.getProcessId());
            }
            
            return R.ok("工序完成成功");
        } catch (Exception e) {
            log.error("工序完成失败", e);
            return R.fail("工序完成失败: " + e.getMessage());
        }
    }
    
    @Override
    public R<Void> changeStep(ChangeProcessStepRequest dto) {
        try {
            log.info("开始变更工序步骤，请求参数：{}", dto);
            
            ChangeProcessStepCommand command = new ChangeProcessStepCommand(
                    dto.getProcessId(),
                    dto.getFromStepId(),
                    dto.getToStepId()
            );
            
            CommandResult<Void> result = changeStepCommandHandler.handle(command);
            
            if (!result.success()) {
                log.warn("工序步骤变更失败，原因：{}", result.msg());
                return R.fail(result.msg());
            }
            
            // 更新读模型（Q端）
            ProcessExecutionViewPo processExecutionView = processExecutionViewService.getById(dto.getProcessId());
            if (processExecutionView != null) {
                processExecutionView.setCurrentStepId(dto.getToStepId());
                processExecutionView.setLastStepChangeTime(LocalDateTime.now());
                processExecutionView.setLastStepChangeType(dto.getChangeType());
                processExecutionView.setLastStepChangeReason(dto.getReason());
                processExecutionView.setLastOperator(dto.getOperatorId());
                processExecutionViewService.updateById(processExecutionView);
                log.info("工序执行读模型更新成功，processId={}", dto.getProcessId());
            }
            
            return R.ok("工序步骤变更成功");
        } catch (Exception e) {
            log.error("工序步骤变更失败", e);
            return R.fail("工序步骤变更失败: " + e.getMessage());
        }
    }
    
    @Override
    public R<Void> checkQuality(CheckProcessQualityRequestDto dto) {
        try {
            log.info("开始工序质量检测，请求参数：{}", dto);
            
            CheckProcessQualityCommand command = new CheckProcessQualityCommand(
                    dto.getProcessId(),
                    dto.getResult()
            );
            
            CommandResult<Void> result = checkQualityCommandHandler.handle(command);
            
            if (!result.success()) {
                log.warn("工序质量检测失败，原因：{}", result.msg());
                return R.fail(result.msg());
            }
            
            // 更新读模型（Q端）
            ProcessExecutionViewPo processExecutionView = processExecutionViewService.getById(dto.getProcessId());
            if (processExecutionView != null) {
                processExecutionView.setQualityCheckResult(dto.getResult());
                processExecutionView.setQualityCheckFailReason(dto.getFailReason());
                processExecutionView.setQualityCheckTime(LocalDateTime.now());
                if ("FAIL".equals(dto.getResult())) {
                    processExecutionView.setStatus("ERROR");
                }
                processExecutionViewService.updateById(processExecutionView);
                log.info("工序执行读模型更新成功，processId={}", dto.getProcessId());
            }
            
            return R.ok("工序质量检测成功");
        } catch (Exception e) {
            log.error("工序质量检测失败", e);
            return R.fail("工序质量检测失败: " + e.getMessage());
        }
    }
    
    @Override
    public R<Void> hold(HoldProcessRequestDto dto) {
        try {
            log.info("开始工序挂起，请求参数：{}", dto);
            
            HoldProcessCommand command = new HoldProcessCommand(
                    dto.getProcessId()
            );
            
            CommandResult<Void> result = holdCommandHandler.handle(command);
            
            if (!result.success()) {
                log.warn("工序挂起失败，原因：{}", result.msg());
                return R.fail(result.msg());
            }
            
            // 更新读模型（Q端）
            ProcessExecutionViewPo processExecutionView = processExecutionViewService.getById(dto.getProcessId());
            if (processExecutionView != null) {
                processExecutionView.setStatus("HOLD");
                processExecutionView.setHoldTime(LocalDateTime.now());
                processExecutionView.setHoldReason(dto.getReason());
                processExecutionView.setLastOperator(dto.getOperatorId());
                processExecutionViewService.updateById(processExecutionView);
                log.info("工序执行读模型更新成功，processId={}", dto.getProcessId());
            }
            
            return R.ok("工序挂起成功");
        } catch (Exception e) {
            log.error("工序挂起失败", e);
            return R.fail("工序挂起失败: " + e.getMessage());
        }
    }
    
    @Override
    public R<Void> release(ReleaseProcessRequestDto dto) {
        try {
            log.info("开始工序解除挂起，请求参数：{}", dto);
            
            ReleaseProcessCommand command = new ReleaseProcessCommand(
                    dto.getProcessId()
            );
            
            CommandResult<Void> result = releaseCommandHandler.handle(command);
            
            if (!result.success()) {
                log.warn("工序解除挂起失败，原因：{}", result.msg());
                return R.fail(result.msg());
            }
            
            // 更新读模型（Q端）
            ProcessExecutionViewPo processExecutionView = processExecutionViewService.getById(dto.getProcessId());
            if (processExecutionView != null) {
                processExecutionView.setStatus("RUNNING");
                processExecutionView.setReleaseTime(LocalDateTime.now());
                processExecutionView.setLastOperator(dto.getOperatorId());
                processExecutionViewService.updateById(processExecutionView);
                log.info("工序执行读模型更新成功，processId={}", dto.getProcessId());
            }
            
            return R.ok("工序解除挂起成功");
        } catch (Exception e) {
            log.error("工序解除挂起失败", e);
            return R.fail("工序解除挂起失败: " + e.getMessage());
        }
    }
    
    @Override
    public R<Void> rework(ReworkProcessRequestDto dto) {
        try {
            log.info("开始工序返工，请求参数：{}", dto);
            
            ReworkProcessCommand command = new ReworkProcessCommand(
                    dto.getProcessId()
            );
            
            CommandResult<Void> result = reworkCommandHandler.handle(command);
            
            if (!result.success()) {
                log.warn("工序返工失败，原因：{}", result.msg());
                return R.fail(result.msg());
            }
            
            // 更新读模型
            ProcessExecutionViewPo processExecutionView = processExecutionViewService.getById(dto.getProcessId());
            if (processExecutionView != null) {
                processExecutionView.setStatus("REWORK");
                processExecutionView.setReworkTime(LocalDateTime.now());
                processExecutionView.setReworkReason(dto.getReason());
                processExecutionView.setLastOperator(dto.getOperatorId());
                processExecutionViewService.updateById(processExecutionView);
                log.info("工序执行读模型更新成功，processId={}", dto.getProcessId());
            }
            
            return R.ok("工序返工成功");
        } catch (Exception e) {
            log.error("工序返工失败", e);
            return R.fail("工序返工失败: " + e.getMessage());
        }
    }
    
    @Override
    public R<Void> recordMeasurement(RecordProcessMeasurementRequestDto dto) {
        try {
            log.info("开始工序测量参数记录，请求参数：{}", dto);
            
            RecordProcessMeasurementCommand command = new RecordProcessMeasurementCommand(
                    dto.getProcessId()
            );
            
            CommandResult<Void> result = recordMeasurementCommandHandler.handle(command);
            
            if (!result.success()) {
                log.warn("工序测量参数记录失败，原因：{}", result.msg());
                return R.fail(result.msg());
            }
            
            // 读模型可根据需要补充参数追溯等信息
            // ...如需补充请告知...
            
            return R.ok("工序测量参数记录成功");
        } catch (Exception e) {
            log.error("工序测量参数记录失败", e);
            return R.fail("工序测量参数记录失败: " + e.getMessage());
        }
    }
    
    @Override
    public R<Void> assign(AssignProcessRequest dto) {
        try {
            log.info("开始工序分配，请求参数：{}", dto);
            
            AssignProcessCommand command = new AssignProcessCommand(
                    dto.getProcessId(),
                    dto.getWorkstationId(),
                    dto.getEquipmentId()
            );
            
            CommandResult<Void> result = assignCommandHandler.handle(command);
            
            if (!result.success()) {
                log.warn("工序分配失败，原因：{}", result.msg());
                return R.fail(result.msg());
            }
            
            // 更新读模型
            ProcessExecutionViewPo processExecutionView = processExecutionViewService.getById(dto.getProcessId());
            if (processExecutionView != null) {
                processExecutionView.setAssignedWorkstationId(dto.getWorkstationId());
                processExecutionView.setAssignedEquipmentId(dto.getEquipmentId());
                processExecutionViewService.updateById(processExecutionView);
                log.info("工序执行读模型更新成功，processId={}", dto.getProcessId());
            }
            
            return R.ok("工序分配成功");
        } catch (Exception e) {
            log.error("工序分配失败", e);
            return R.fail("工序分配失败: " + e.getMessage());
        }
    }
    
    @Override
    public R<Page<ProcessViewPo>> list(Page<ProcessViewPo> page, ProcessViewPo query) {
        try {
            log.info("开始分页查询工序列表，页码：{}，页大小：{}，查询条件：{}", page.getCurrent(), page.getSize(), query);
            
            LambdaQueryWrapper<ProcessViewPo> queryWrapper = new LambdaQueryWrapper<>();
            
            // 构建查询条件
            if (StringUtils.hasText(query.getProcessCode())) {
                queryWrapper.like(ProcessViewPo::getProcessCode, query.getProcessCode());
            }
            if (StringUtils.hasText(query.getProcessName())) {
                queryWrapper.like(ProcessViewPo::getProcessName, query.getProcessName());
            }
            if (StringUtils.hasText(query.getStatus())) {
                queryWrapper.eq(ProcessViewPo::getStatus, query.getStatus());
            }
            if (query.getWorkOrderId() != null) {
                queryWrapper.eq(ProcessViewPo::getWorkOrderId, query.getWorkOrderId());
            }
            if (query.getWorkstationId() != null) {
                queryWrapper.eq(ProcessViewPo::getWorkstationId, query.getWorkstationId());
            }
            if (query.getEquipmentId() != null) {
                queryWrapper.eq(ProcessViewPo::getEquipmentId, query.getEquipmentId());
            }
            
            // 按创建时间倒序排列
            queryWrapper.orderByDesc(ProcessViewPo::getCreatedTime);
            
            Page<ProcessViewPo> result = processViewService.page(page, queryWrapper);
            log.info("工序列表查询成功，总记录数：{}，当前页记录数：{}", result.getTotal(), result.getRecords().size());
            
            return R.ok(result, "工序列表查询成功");
        } catch (Exception e) {
            log.error("工序列表查询失败", e);
            return R.fail("工序列表查询失败: " + e.getMessage());
        }
    }
    
    @Override
    public R<ProcessViewPo> getById(Long processId) {
        try {
            log.info("开始查询工序详情，processId：{}", processId);
            
            if (processId == null || processId <= 0) {
                log.warn("工序ID无效：{}", processId);
                return R.fail("工序ID不能为空且必须为正整数");
            }
            
            ProcessViewPo processView = processViewService.getById(processId);
            if (processView == null) {
                log.warn("工序不存在，processId：{}", processId);
                return R.fail("工序不存在");
            }
            
            log.info("工序详情查询成功，processId：{}", processId);
            return R.ok(processView, "工序详情查询成功");
        } catch (Exception e) {
            log.error("工序详情查询失败，processId：{}", processId, e);
            return R.fail("工序详情查询失败: " + e.getMessage());
        }
    }
    
    @Override
    public R<Page<ProcessViewPo>> getByStatus(Page<ProcessViewPo> page, String status) {
        try {
            log.info("开始按状态查询工序列表，页码：{}，页大小：{}，状态：{}", page.getCurrent(), page.getSize(), status);
            
            if (!StringUtils.hasText(status)) {
                log.warn("工序状态不能为空");
                return R.fail("工序状态不能为空");
            }
            
            LambdaQueryWrapper<ProcessViewPo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ProcessViewPo::getStatus, status);
            queryWrapper.orderByDesc(ProcessViewPo::getCreatedTime);
            
            Page<ProcessViewPo> result = processViewService.page(page, queryWrapper);
            log.info("按状态查询工序列表成功，状态：{}，总记录数：{}，当前页记录数：{}", status, result.getTotal(), result.getRecords().size());
            
            return R.ok(result, "按状态查询工序列表成功");
        } catch (Exception e) {
            log.error("按状态查询工序列表失败，状态：{}", status, e);
            return R.fail("按状态查询工序列表失败: " + e.getMessage());
        }
    }
    
    @Override
    public R<Void> delete(Long processId) {
        try {
            log.info("开始删除工序，processId：{}", processId);
            
            if (processId == null || processId <= 0) {
                log.warn("工序ID无效：{}", processId);
                return R.fail("工序ID不能为空且必须为正整数");
            }
            
            ProcessViewPo processView = processViewService.getById(processId);
            if (processView == null) {
                log.warn("工序不存在，processId：{}", processId);
                return R.fail("工序不存在");
            }
            
            // 检查工序状态，只有特定状态的工序才能删除
            if (!"created".equals(processView.getStatus()) && !"completed".equals(processView.getStatus())) {
                log.warn("工序状态不允许删除，processId：{}，状态：{}", processId, processView.getStatus());
                return R.fail("只有已创建或已完成状态的工序才能删除");
            }
            
            boolean deleted = processViewService.removeById(processId);
            if (deleted) {
                log.info("工序删除成功，processId：{}", processId);
                return R.ok("工序删除成功");
            } else {
                log.warn("工序删除失败，processId：{}", processId);
                return R.fail("工序删除失败");
            }
        } catch (Exception e) {
            log.error("工序删除失败，processId：{}", processId, e);
            return R.fail("工序删除失败: " + e.getMessage());
        }
    }
    
    @Override
    public R<Void> batchDelete(List<Long> processIds) {
        try {
            log.info("开始批量删除工序，processIds：{}", processIds);
            
            if (processIds == null || processIds.isEmpty()) {
                log.warn("工序ID列表不能为空");
                return R.fail("工序ID列表不能为空");
            }
            
            // 验证ID列表中的每个ID都是有效的正整数
            for (Long id : processIds) {
                if (id == null || id <= 0) {
                    log.warn("工序ID列表中包含无效的ID：{}", id);
                    return R.fail("工序ID列表中包含无效的ID: " + id);
                }
            }
            
            if (processIds.size() > 100) {
                log.warn("一次删除的工序数量过多：{}", processIds.size());
                return R.fail("一次最多只能删除100个工序");
            }
            
            // 检查所有工序的状态
            List<ProcessViewPo> processViews = processViewService.listByIds(processIds);
            if (processViews.size() != processIds.size()) {
                log.warn("部分工序不存在，请求删除数量：{}，实际存在数量：{}", processIds.size(), processViews.size());
                return R.fail("部分工序不存在");
            }
            
            for (ProcessViewPo processView : processViews) {
                if (!"created".equals(processView.getStatus()) && !"completed".equals(processView.getStatus())) {
                    log.warn("工序状态不允许删除，processId：{}，状态：{}", processView.getId(), processView.getStatus());
                    return R.fail("只有已创建或已完成状态的工序才能删除，工序ID: " + processView.getId());
                }
            }
            
            boolean deleted = processViewService.removeByIds(processIds);
            if (deleted) {
                log.info("批量删除工序成功，删除数量：{}", processIds.size());
                return R.ok("批量删除工序成功");
            } else {
                log.warn("批量删除工序失败，processIds：{}", processIds);
                return R.fail("批量删除工序失败");
            }
        } catch (Exception e) {
            log.error("批量删除工序失败，processIds：{}", processIds, e);
            return R.fail("批量删除工序失败: " + e.getMessage());
        }
    }
}